//Derek Connell (conned2) 2/10/10

#include <cstdio>
#include <cassert>
#include <vector>
#include <iostream>
#include <map>
// Included files for OpenGL Rendering
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#endif

#include "mesh.h"
#include "edge.h"
#include "vertex.h"
#include "triangle.h"
#include "glCanvas.h"

using namespace std;

int deleteRepeats(vector<Triangle*> tobedeleted,vector<Triangle*> atriangles,vector<Triangle*> btriangles, Vertex * apoint, Vertex * bpoint);
int Triangle::next_triangle_id = 0;


// =======================================================================
// MESH DESTRUCTOR 
// =======================================================================

Mesh::~Mesh() {
  // delete all the triangles
  std::vector<Triangle*> todo;
  for (triangleshashtype::iterator iter = triangles.begin();
       iter != triangles.end(); iter++) {
    Triangle *t = iter->second;
    todo.push_back(t);
  }
  int num_triangles = todo.size();
  for (int i = 0; i < num_triangles; i++) {
    removeTriangle(todo[i]);
  }
  // delete all the vertices
  int num_vertices = numVertices();
  for (int i = 0; i < num_vertices; i++) {
    delete vertices[i];
  }
}

// =======================================================================
// MODIFIERS:   ADD & REMOVE
// =======================================================================

Vertex* Mesh::addVertex(const Vec3f &position) {
  int index = numVertices();
  Vertex *v = new Vertex(index, position);
  vertices.push_back(v);
  if (numVertices() == 1)
    bbox = BoundingBox(position,position);
  else 
    bbox.Extend(position);
  return v;
}


void Mesh::addTriangle(Vertex *a, Vertex *b, Vertex *c) {
  // create the triangle
  Triangle *t = new Triangle();
  // create the edges
  Edge *ea = new Edge(a,b,t);
  Edge *eb = new Edge(b,c,t);
  Edge *ec = new Edge(c,a,t);
  // point the triangle to one of its edges
  t->setEdge(ea);
  // connect the edges to each other
  ea->setNext(eb);
  eb->setNext(ec);
  ec->setNext(ea);
  // verify these edges aren't already in the mesh 
  // (which would be a bug, or a non-manifold mesh)
  /*assert (edges.find(std::make_pair(a,b)) == edges.end());
  assert (edges.find(std::make_pair(b,c)) == edges.end());
  assert (edges.find(std::make_pair(c,a)) == edges.end());*/
  // add the edges to the master list
  edges[std::make_pair(a,b)] = ea;
  edges[std::make_pair(b,c)] = eb;
  edges[std::make_pair(c,a)] = ec;
  // connect up with opposite edges (if they exist)
  edgeshashtype::iterator ea_op = edges.find(std::make_pair(b,a)); 
  edgeshashtype::iterator eb_op = edges.find(std::make_pair(c,b)); 
  edgeshashtype::iterator ec_op = edges.find(std::make_pair(a,c)); 
  if (ea_op != edges.end()) { ea_op->second->setOpposite(ea); }
  if (eb_op != edges.end()) { eb_op->second->setOpposite(eb); }
  if (ec_op != edges.end()) { ec_op->second->setOpposite(ec); }
  // add the triangle to the master list
  assert (triangles.find(t->getID()) == triangles.end());
  triangles[t->getID()] = t;
}


void Mesh::removeTriangle(Triangle *t) {
  Edge *ea = t->getEdge();
  Edge *eb = ea->getNext();
  Edge *ec = eb->getNext();
  Vertex *a = ea->getStartVertex();
  Vertex *b = eb->getStartVertex();
  Vertex *c = ec->getStartVertex();
  // remove these elements from master lists
  edges.erase(std::make_pair(a,b)); 
  edges.erase(std::make_pair(b,c)); 
  edges.erase(std::make_pair(c,a)); 
  triangles.erase(t->getID());
  // clean up memory
  delete ea;
  delete eb;
  delete ec;
  delete t;
}


// =======================================================================
// Helper functions for accessing data in the hash table
// =======================================================================

Edge* Mesh::getMeshEdge(Vertex *a, Vertex *b) const {
  edgeshashtype::const_iterator iter = edges.find(std::make_pair(a,b));
  if (iter == edges.end()) return NULL;
  return iter->second;
}

Vertex* Mesh::getChildVertex(Vertex *p1, Vertex *p2) const {
  vphashtype::const_iterator iter = vertex_parents.find(std::make_pair(p1,p2)); 
  if (iter == vertex_parents.end()) return NULL;
  return iter->second; 
}

void Mesh::setParentsChild(Vertex *p1, Vertex *p2, Vertex *child) {
  assert (vertex_parents.find(std::make_pair(p1,p2)) == vertex_parents.end());
  vertex_parents[std::make_pair(p1,p2)] = child; 
}


// =======================================================================
// the load function parses very simple .obj files
// the basic format has been extended to allow the specification 
// of crease weights on the edges.
// =======================================================================

void Mesh::Load(const char *input_file) {
  
  std::cout << "Opening file " << input_file << std::endl;
  FILE *objfile = fopen(input_file,"r");
  if (objfile == NULL) {
    printf ("ERROR! CANNOT OPEN '%s'\n",input_file);
    return;
  }

  char line[200];
  char token[100];
  char atoken[100];
  char btoken[100];
  char ctoken[100];
  float x,y,z;
  int a,b,c,d,e;
  
  int index = 0;
  int vert_count = 0;
  int vert_index = 1;
  
  while (fgets(line, 200, objfile)) {   
    int token_count = sscanf (line, "%s\n",token);
    if (token_count == -1) continue;
    a = b = c = d = e = -1;
    if (!strcmp(token,"usemtl") ||
	!strcmp(token,"g")) {
      vert_index = 1; 
      index++;
    } else if (!strcmp(token,"v")) {
      vert_count++;
      sscanf (line, "%s %f %f %f\n",token,&x,&y,&z);
      addVertex(Vec3f(x,y,z));
    } else if (!strcmp(token,"f")) {
      int num = sscanf (line, "%s %s %s %s\n",token,
			atoken,btoken,ctoken);
      sscanf (atoken,"%d",&a);
      sscanf (btoken,"%d",&b);
      sscanf (ctoken,"%d",&c);
      assert (num == 4);
      a -= vert_index;
      b -= vert_index;
      c -= vert_index;
      assert (a >= 0 && a < numVertices());
      assert (b >= 0 && b < numVertices());
      assert (c >= 0 && c < numVertices());
      addTriangle(getVertex(a),getVertex(b),getVertex(c)); 
    } else if (!strcmp(token,"e")) {
      int num = sscanf (line, "%s %s %s %s\n",token,atoken,btoken,ctoken);
      assert (num == 4);
      sscanf (atoken,"%d",&a);
      sscanf (btoken,"%d",&b);
      if (!strcmp(ctoken,"inf")) x = 1000000; // this is close to infinity...
      else sscanf (ctoken,"%f",&x);
      Vertex *va = getVertex(a);
      Vertex *vb = getVertex(b);
      Edge *ab = getMeshEdge(va,vb);
      Edge *ba = getMeshEdge(vb,va);
      assert (ab != NULL);
      assert (ba != NULL);
      ab->setCrease(x);
      ba->setCrease(x);
    } else if (!strcmp(token,"vt")) {
    } else if (!strcmp(token,"vn")) {
    } else if (token[0] == '#') {
    } else {
      printf ("LINE: '%s'",line);
    }
  }
  
  Vec3f temp;
  for (int i = 0; i < numVertices(); ++i)
  {
      
      temp = getVertex(i)->getPos() - getVertex(0)->getPos();
      std::cout << "local pos = " << temp << std::endl;
      localAdjust.push_back(temp);
  }
 
}


// =======================================================================
// PAINT
// =======================================================================

Vec3f ComputeNormal(const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) {
  Vec3f v12 = p2;
  v12 -= p1;
  Vec3f v23 = p3;
  v23 -= p2;
  Vec3f normal;
  Vec3f::Cross3(normal,v12,v23);
  normal.Normalize();
  return normal;
}

void InsertNormal(const Vec3f &p1, const Vec3f &p2, const Vec3f &p3) {
  Vec3f normal = ComputeNormal(p1,p2,p3);
  glNormal3f(normal.x(), normal.y(), normal.z());
}

void Mesh::Paint(ArgParser *args, int curmouseX, int curmouseY) {


  // scale it so it fits in the window
  Vec3f center; bbox.getCenter(center);
  float s = 1/bbox.maxDim();
  glScalef(s,s,s);
  glTranslatef(-center.x(),-center.y(),-center.z());

  // this offset prevents "z-fighting" bewteen the edges and faces
  // the edges will always win.
  glEnable(GL_POLYGON_OFFSET_FILL);
  glPolygonOffset(1.1,4.0);

  glColor3f(1,1,1);

  /*glBegin (GL_TRIANGLES);
  std::cout << "paintin'" << std::endl;
  for (triangleshashtype::iterator iter = triangles.begin(); iter != triangles.end(); iter++) 
  {
      Triangle *t = iter->second;
      Vec3f a = (*t)[0]->getPos();
      //if (iter == triangles.begin()) std::cout << a << std::endl;
      Vec3f b = (*t)[1]->getPos();
      Vec3f c = (*t)[2]->getPos();
      InsertNormal(a,b,c); 
      glVertex3f(a.x(),a.y(),a.z());
      glVertex3f(b.x(),b.y(),b.z());
      glVertex3f(c.x(),c.y(),c.z());
      
  }


  glEnd();*/
  
  

   glDisable(GL_POLYGON_OFFSET_FILL); 
   //Alles wird wie vorher
   //glDisable(GL_BLEND);
   //glEnable(GL_DEPTH_TEST);
   ///////////////////////////////////////////////////////////
   
   



  // =================================
  if (args->wireframe) {
    glDisable(GL_LIGHTING);

    // draw all the interior, non-crease edges
    glLineWidth(1);
    glColor3f(0,0,0);
    glBegin (GL_LINES);
    for (edgeshashtype::iterator iter = edges.begin();
	 iter != edges.end(); iter++) {
      Edge *e = iter->second;
      if (e->getOpposite() == NULL || e->getCrease() > 0) continue;
      Vec3f a = e->getStartVertex()->getPos();
      Vec3f b = e->getEndVertex()->getPos();
      glVertex3f(a.x(),a.y(),a.z());
      glVertex3f(b.x(),b.y(),b.z());
    }
    glEnd();

    // draw all the interior, crease edges
    glLineWidth(3);
    glColor3f(1,1,0);
    glBegin (GL_LINES);
    for (edgeshashtype::iterator iter = edges.begin();
	 iter != edges.end(); iter++) {
      Edge *e = iter->second;
      if (e->getOpposite() == NULL || e->getCrease() == 0) continue;
      Vec3f a = e->getStartVertex()->getPos();
      Vec3f b = e->getEndVertex()->getPos();
      glVertex3f(a.x(),a.y(),a.z());
      glVertex3f(b.x(),b.y(),b.z());
    }
    glEnd();

    // draw all the boundary edges
    glLineWidth(3);
    glColor3f(1,0,0);
    glBegin (GL_LINES);
    for (edgeshashtype::iterator iter = edges.begin();
	 iter != edges.end(); iter++) {
      Edge *e = iter->second;
      if (e->getOpposite() != NULL) continue;
      assert (e->getCrease() == 0);
      Vec3f a = e->getStartVertex()->getPos();
      Vec3f b = e->getEndVertex()->getPos();
      glVertex3f(a.x(),a.y(),a.z());
      glVertex3f(b.x(),b.y(),b.z());
    }
    glEnd();

    glEnable(GL_LIGHTING);
  }

  HandleGLError(); 
}

// =================================================================
// SUBDIVISION
// =================================================================

void Mesh::LoopSubdivision() {
  printf ("Subdivide the mesh!\n");


  
  vector<Vec3f> a_cords; // store the coordinates of every triangle, keeping track of their midpoints for the subdividing
  vector<Vec3f> b_cords;
  vector<Vec3f> c_cords;
  vector<Vec3f> abM_cords;
  vector<Vec3f> acM_cords;
  vector<Vec3f> bcM_cords;
  
    for (triangleshashtype::iterator iter = triangles.begin();iter != triangles.end(); iter++) 
    {
          Triangle *t = iter->second;
          
          Vec3f a = (*t)[0]->getPos();
          Vec3f b = (*t)[1]->getPos();
          Vec3f c = (*t)[2]->getPos();
          Vec3f abM,acM,bcM;
    
          abM.Set((a.x()+b.x())/2, (a.y()+b.y())/2, (a.z()+b.z())/2);
          acM.Set((a.x()+c.x())/2, (a.y()+c.y())/2, (a.z()+c.z())/2);   
          bcM.Set((b.x()+c.x())/2, (b.y()+c.y())/2, (b.z()+c.z())/2);
          
          a_cords.push_back(a);
          b_cords.push_back(b);
          c_cords.push_back(c);
          abM_cords.push_back(abM);
          acM_cords.push_back(acM);
          bcM_cords.push_back(bcM);
          

    }


  while (numTriangles() > 0)   // Code necessary to destroy all triangles. Carefully structured as to avoid seg faults
    {
       triangleshashtype::iterator iter = triangles.begin();
       removeTriangle(iter->second);
    }


  glBegin (GL_TRIANGLES);    
  for (unsigned int i = 0; i < a_cords.size(); ++i)
   {
           Vec3f a = a_cords[i];
           Vec3f b = b_cords[i];
           Vec3f c = c_cords[i];
           Vec3f abM = abM_cords[i];
           Vec3f acM = acM_cords[i];
           Vec3f bcM = bcM_cords[i];
           
           Vertex * avert = addVertex(a);
           Vertex * bvert = addVertex(b);
           Vertex * cvert = addVertex(c);
           Vertex * abMvert = addVertex(abM);
           Vertex * acMvert = addVertex(acM);
           Vertex * bcMvert = addVertex(bcM);
           
          
          addTriangle(acMvert,avert,abMvert); 
          addTriangle(abMvert,bvert,bcMvert); 
          addTriangle(acMvert,bcMvert,cvert); 
          addTriangle(bcMvert,acMvert,abMvert); 
         
   }
    glEnd();
    
    Vec3f temp1, temp2;         // A bunch of for loops. It checks every edge to every other edge to have correct Opposite edges

    for (triangleshashtype::iterator iter = triangles.begin();iter != triangles.end(); iter++) 
    {
          Triangle *t = iter->second;
 
        for (triangleshashtype::iterator iter2 = triangles.begin();iter2 != triangles.end(); iter2++) 
        {
              Triangle *t2 = iter2->second;     
              
              Edge * edge1 = t->getEdge();
              Edge * edge2 = t2->getEdge();
                    
              for (int i = 0; i < 3; ++i)
              {
                  if (i > 0) edge1 = edge1->getNext();
                  
                  for (int j = 0; j < 3; ++j)
                  {
                      if (j == 0) edge2 = t2->getEdge();
                      else if (j > 0) edge2 = edge2->getNext();
                      
                      if (edge1->getStartVertex() != edge2->getStartVertex() && edge1->getEndVertex() != edge2->getEndVertex())
                      {
                         temp1 = edge1->getStartVertex()->getPos();
                         temp2 = edge2->getStartVertex()->getPos();
                         
                         if (temp1.x() == temp2.x() && temp1.y() == temp2.y() && temp1.z() == temp2.z())
                         {
                               if (edge1->getOpposite() == NULL && edge2->getOpposite() == NULL)
                                  edge1->setOpposite(edge2);
                         }
                      }                               
                  }
              }
              
        }
        
   }
    
    
          
}


// =================================================================
// SIMPLIFICATION
// =================================================================

void Mesh::Simplification(int target_tri_count) {
  

  printf ("Simplify the mesh! %d -> %d\n", numTriangles(), target_tri_count);
  int repeat = (numTriangles() - target_tri_count) / 2;  

  for (int i=0; i < repeat; ++i) // will repeat until 10% of the triangles are removed
      Do_Simplification();

}

void Mesh::Do_Simplification()
{
     
  vertex_parents.clear();
  for (int i=0; i<numVertices(); ++i)
  {
      if(getVertex(i)->erased == false) // if the vertex is not marked for deletion, grab one of it's edges
      {
         getVertex(i)->adjacentverts.clear();
         for (int j=0; j<numVertices(); ++j)
         {
             if (i != j)
             {
                Vertex *apoint = getVertex(i);
                Vertex *bpoint = getVertex(j);
                Edge *e = getMeshEdge(apoint,bpoint);
                if(e!=NULL)
                {
                     make_pair(bpoint->getIndex(),e->Length());
                     apoint->adjacentverts.push_back(bpoint->getIndex());
                }
             }
         }
      }
  }
  
   map<float, pair<int,int> > legal_edges; // I found a map to be the best way to store the valid edges (the ones with an opposite)
  for(int i=0; i<numVertices(); i++)       
  {
	if(getVertex(i)->erased==false)
	{
		Vertex *a=getVertex(i);
		for(unsigned int j=0; j<a->adjacentverts.size(); j++)
		{
			Vertex *b=getVertex(a->adjacentverts[j]);
			int count=0;
			for(unsigned int k=0; k<b->adjacentverts.size(); k++)
			{
				for(unsigned int l=0; l<a->adjacentverts.size(); l++)
				{
					if(b->adjacentverts[k]==a->adjacentverts[l])
						count++;
				}
			}
			if (count<=2)
			{
				
				Edge *e=getMeshEdge(a,b);
				map<float,pair<int,int> >::iterator iter = legal_edges.find(e->Length());
				bool already_there=false; // this boolean is necessary to avoid simplifying an edge twice
				
				while( iter != legal_edges.end() )
				{
					if(iter->second.second==a->getIndex())
					{
						already_there=true;
						break;
					}		
					iter++;
				}
				if(already_there == false && e->Length() != 0)
					legal_edges[e->Length()]=make_pair(a->getIndex(),b->getIndex());
                make_pair(a->getIndex(),b->getIndex());
			}	
		}
	}
  }

  map<float, pair<int,int> >::iterator iter;           // make sure to readjust the positions of adjacent vertices accordingly
  iter=legal_edges.begin();
  dec = dec + 2;
  Vertex *apoint=getVertex(iter->second.first);
  Vertex *bpoint=getVertex(iter->second.second);

  
  Vec3f pos=apoint->getPos();
  for(int i=0; i<numVertices(); i++)
  {
	Vertex *a2=getVertex(i);
	Vec3f a2_pos=a2->getPos();
	if(a2->getIndex() != apoint->getIndex() && a2_pos == pos)
	{
		a2->setPos(bpoint->getPos());
	}
  }
  
  apoint->setPos(bpoint->getPos());
  apoint->erased=true;
  
  
  
}



